package cn.ante.ymcc.service.impl;

import cn.ante.ymcc.constant.Constance;
import cn.ante.ymcc.doc.CourseDoc;
import cn.ante.ymcc.domain.*;
import cn.ante.ymcc.dto.CourseAddDto;
import cn.ante.ymcc.dto.CourseDto;
import cn.ante.ymcc.dto.LoginJwtInfoDto;
import cn.ante.ymcc.dto.MessagePushDto;
import cn.ante.ymcc.feign.CouserSearchFeignClient;
import cn.ante.ymcc.feign.MediaFeignClient;
import cn.ante.ymcc.mapper.CourseMapper;
import cn.ante.ymcc.mq.producer.CourseProducer;
import cn.ante.ymcc.result.JSONResult;
import cn.ante.ymcc.service.*;
import cn.ante.ymcc.util.AssertUtil;
import cn.ante.ymcc.utills.LoginYmccContext;
import cn.ante.ymcc.vo.Course2OrderInfoVo;
import cn.ante.ymcc.vo.CourseDetailVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Nai
 * @since 2022-08-08
 */
@Service
@Transactional
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {
    @Autowired
    private ICourseService courseService;

    @Autowired
    private ICourseDetailService courseDetailService;

    @Autowired
    private ICourseMarketService courseMarketService;

    @Autowired
    private ICourseResourceService courseResourceService;

    @Autowired
    private ITeacherService teacherService;

    @Autowired
    private ICourseSummaryService courseSummaryService;

    @Autowired
    private ICourseTeacherService courseTeacherService;

    @Autowired
    private CouserSearchFeignClient couserSearchFeignClient;

    @Autowired
    private ICourseTypeService courseTypeService;

    @Autowired
    private CourseProducer courseProducer;

    @Autowired
    private MediaFeignClient mediaFeignClient;
    
    @Autowired
    private ICourseChapterService courseChapterService;

    @Override
    public JSONResult save(CourseAddDto courseAddDto) {
        Course course = courseAddDto.getCourse();
        CourseDetail courseDetail = courseAddDto.getCourseDetail();
        CourseMarket courseMarket = courseAddDto.getCourseMarket();
        List<Long> teacharIds = courseAddDto.getTeacharIds();
        CourseResource courseResource = courseAddDto.getCourseResource();
        // 课程信息增加,添加老师的信息
        List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        String s = teachers.stream().map(teacher -> teacher.getName()).collect(Collectors.joining(","));
        course.setTeacherNames(s);
        course.setStatus(Constance.CourseState.COURSE_OFFLINE);
        // 添加课程的登陆者  和登陆人用户名
        LoginJwtInfoDto loginContext = LoginYmccContext.getLoginContext();
        course.setLoginId(loginContext.getId());
        course.setLoginUserName(loginContext.getUsername());
        courseService.insert(course);
        // 保存中间表
        CourseTeacher courseTeacher = new CourseTeacher();
        courseTeacher.setCourseId(course.getId());
        if (teachers != null) {
            for (Teacher t : teachers) {
                courseTeacher.setTeacherId(t.getId());
            }
        }
        courseTeacherService.insert(courseTeacher);

        // 课程详情增加
        courseDetail.setId(course.getId());
        courseDetailService.insert(courseDetail);
        // 课程销售增加
        courseMarket.setId(course.getId());
        courseMarketService.insert(courseMarket);
        // 课程资源增加
        courseResource.setCourseId(course.getId());
        courseResourceService.insert(courseResource);
        // 课程统计增加
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        courseSummaryService.insert(courseSummary);
        return JSONResult.success();
    }


    /**
     * 1.参数校验
     * 2.业务校验
     *  找不到课程
     *  课程状态不是下架
     * 3.修改课程状态为上架，添加上架时间
     * 4.把课程需要搜索的相关内容放入ES中
     * ==== 为Search服务集成Es（SpringBoot集成）
     *  4.1 为Search服务编写controller保存数据到Es
     *  4.2 为Search服务编写公共的Feign-api
     *  4.3 依赖Feign-api调用Search服务的controller保存课程到Es
     * @param courseId
     */
    @Override
    @Transactional
    public JSONResult onLineCourse(Long courseId) {
        // 判断id是否为空
        AssertUtil.isNotNull(courseId,"课程id不能为空");

        // 通过id查询到课程信息
        Course course = courseService.selectById(courseId);

        // 判断通过id拿到的课程信息不为空时
        AssertUtil.isNotNull(course,"查不到课程");

        // 判断课程的状态不是下架
        AssertUtil.isTrue(course.getStatus() == Constance.CourseState.COURSE_OFFLINE,"商品已上架");

        // 就将其状态改为上线，并且设置上线时间
        course.setStatus(Constance.CourseState.COURSE_ONLINE); // 可以将魔法值取出来
        course.setOnlineTime(new Date());
        courseService.updateById(course);

        // 课程修改成功后，调用feign接口将其保存到es中，便于之后全文搜素
        CourseDoc courseDoc = new CourseDoc();
        CourseSummary courseSummary = courseSummaryService.selectById(course.getId());
        CourseMarket courseMarket = courseMarketService.selectById(course.getId());
        CourseType courseType = courseTypeService.selectById(course.getCourseTypeId());

        // 将总计/市场销售、课程拷贝给文档
        BeanUtils.copyProperties(courseSummary,courseDoc);
        BeanUtils.copyProperties(courseMarket,courseDoc);
        BeanUtils.copyProperties(course,courseDoc);

        // 收费标准、类型名字、id重现设置
        courseDoc.setChargeName(courseMarket.getCharge().intValue() == 1 ? "免费" : "收费");
        courseDoc.setCourseTypeName(courseType.getName());

        // 由于每一次深拷贝都会有id被拷贝，所以将其置为课程的id
        courseDoc.setId(courseId);
        JSONResult jsonResult = couserSearchFeignClient.saveElasticSearch(courseDoc);
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程发布失败");

        // 推送消息,设置消息相关的内容
        MessagePushDto messagePushDto = new MessagePushDto();
        messagePushDto.setContent(course.getName());
        ServletRequestAttributes servletRequestAttributes =  (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
        messagePushDto.setIp( httpServletRequest.getRemoteAddr());
        courseProducer.sendSmsMeassage(messagePushDto);
        return JSONResult.success();
    }


    /**
    * @Title: 下架流程
    * @Description: TODO
    * @Author: Nai
    * @Version: 1.0
    * @Date:  2022/8/14 18:48
    * @Parameters: [courseId]
    * @Return cn.ante.ymcc.result.JSONResult
    */
    @Override
    public JSONResult offLineCourse(Long courseId) {
        // 判断传入的id
        AssertUtil.isNotNull(courseId,"课程id不能为空");
        // 根据id查找到该课程信息
        Course course = courseService.selectById(courseId);
        // 查看该课程的状态
        AssertUtil.isFalse(course.getStatus()==Constance.CourseState.COURSE_OFFLINE,"课程已经下架");
        // 将课程的状态改为下线
        course.setStatus(Constance.CourseState.COURSE_OFFLINE);
        // 保存课程状态
        courseService.updateById(course);
        // 调用feign
        JSONResult jsonResult = couserSearchFeignClient.removeElasticSearch(courseId);
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程下架失败");
        return JSONResult.success();
    }

    /**
    * @Description: 课程前台详情页展示
    * @Author: Nai
    * @Version: 1.0
    * @Date:  2022/8/17 21:06
    */
    @Override
    public CourseDetailVo getCourseDetail(Long courseId) {
        // 判空
        AssertUtil.isNotNull(courseId,"课程id不能为空");

        // 根据id查询到相关的课程信息
        Course course = courseService.selectById(courseId);

        // 判断课程是否上架
        Integer status = course.getStatus();
        boolean b = status == Constance.CourseState.COURSE_ONLINE;
        AssertUtil.isTrue(b,"非法参数！！！");


        // 判断课程不为空
        AssertUtil.isNotNull(course,"非法参数");

        // 根据id查询到课程的详情
        CourseDetail courseDetail = courseDetailService.selectById(courseId);

        AssertUtil.isNotNull(courseDetail,"非法参数请求");

        // 根据id查询到销售市场信息
        CourseMarket courseMarket = courseMarketService.selectById(courseId);

        // 根据id查询到教师信息
        Wrapper<CourseTeacher> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id",courseId);
        List<CourseTeacher> courseTeachers = courseTeacherService.selectList(wrapper);
        List<Long> ids = courseTeachers.stream()
                .map(CourseTeacher::getTeacherId).collect(Collectors.toList());
        List<Teacher> teachers = teacherService.selectBatchIds(ids);

        // 根据id找到该课程得所有章节
        Wrapper<CourseChapter> coursetypeWrapper = new EntityWrapper<>();
        coursetypeWrapper.eq("course_id",courseId);
        List<CourseChapter> courseChapters = courseChapterService.selectList(coursetypeWrapper);
        Map<Long, CourseChapter> courseChaptermap = courseChapters.stream()
                .collect(Collectors.toMap(CourseChapter::getId, CourseChapter -> CourseChapter));
        
        // 根据id查找到相关课程的章节，然后将章节下的视频找到
        JSONResult result = mediaFeignClient.getMediaByCourseId(courseId);
        AssertUtil.isTrue(JSONResult.success().isSuccess(),JSONResult.error().getMessage());
        AssertUtil.isNotNull(result.getData(),"没有找到视频嚄");
        List<MediaFile> mediaFiles = JSON.parseArray(result.getData().toString(), MediaFile.class);

        // 遍历课程视频，然后将视频放到课程章节中去
        mediaFiles.stream().forEach(mediaFile -> {
            Long chapterId = mediaFile.getChapterId();
            AssertUtil.isNotNull(chapterId,"章节为空");
            courseChaptermap.get(chapterId).getMediaFiles().add(mediaFile);
        });
        return new CourseDetailVo(course,courseDetail,courseMarket,teachers,courseChapters);
    }

    /**
    * @Description: 加入购物车之后得结算页面
    * @Author: Nai
    * @Version: 1.0
    * @Date:  2022/8/17 23:40
    */
    @Override
    public Course2OrderInfoVo courseOrderInfo(String courseIds) {
        // 判断传过来的值的合法性
        AssertUtil.isNotNull(courseIds,"参数为空");

        // 将string类型的ids转换成一个long类型的集合
        String[] ids = courseIds.split(",");
        // 根据ids批量查询到课程
        List<Course> courses = selectBatchIds(Arrays.asList(ids));

        // 新建一个返回给前端的对象
        Course2OrderInfoVo course2OrderInfoVo = new Course2OrderInfoVo();

        // 将对象中的list集合拿出来，装含有课程信息和课程销量信息的对象coursedto
        List<CourseDto> courseInfos = course2OrderInfoVo.getCourseInfos();

        // 遍历课程集合
        courses.stream().forEach(course -> {
            // 判断得到的课程的状态是不是已经上架的课程
            boolean online = course.getStatus() == Constance.CourseState.COURSE_ONLINE;
            AssertUtil.isTrue(online,"非法参数");

            // 根据课程的id得到相应课程的销量对象
            CourseMarket courseMarket = courseMarketService.selectById(course.getId());

            // 将课程何课程销量对象设置给返回前端参数中的课程信息集合之中
            courseInfos.add(new CourseDto(course,courseMarket));

            // 设置返回给前端用户对象中的总金额的值，先将返回给前端用户的总金额拿出来然后加上当前遍历得到的课程销量对象的价格
            course2OrderInfoVo.setTotalAmount(course2OrderInfoVo.getTotalAmount().add(courseMarket.getPrice()));

        });
        // 将最后封装成功的CourseInfos设置到对象的字段中去
        course2OrderInfoVo.setCourseInfos(courseInfos);
        return course2OrderInfoVo;
    }
}
